function debounce(fn: Function, delay: number): Function {

    let timer: string | number | NodeJS.Timeout | undefined;

    /* 加过防抖的新fn */
    return function newFn(...args: any[]) {

        // 先顶掉上次没有到时的timer
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            // null = 不改变this的指向
            fn.apply(null, args)

            clearTimeout(timer)
            timer = undefined
        }, delay);

    }
}

import { DirectiveBinding, VNode } from 'vue';

interface MyBindingValue {
    delay: number,
    handler: (ev: HTMLElementEventMap) => any
}

interface MyBinding {
    arg: string,
    value: MyBindingValue
}

interface MyVNode extends VNode {
    eventType: string,
    eventHandler: EventListenerOrEventListenerObject
}

interface MyVNode2 {
    eventType: string,
    eventHandler: EventListenerOrEventListenerObject
}

/* 
v-debounce:input="{delay: 1000,handler: onInput}"
*/
export default {
    name: "debounce",
    handler: {
        /* 目标元素所在的组件挂载 */
        mounted(el: HTMLElement, binding: DirectiveBinding, vnode: MyVNode) {
            const { arg, value: { delay, handler } } = binding
            vnode["eventType"] = arg as string
            vnode["eventHandler"] = debounce(handler, delay) as EventListenerOrEventListenerObject

            el.addEventListener(vnode["eventType"], vnode["eventHandler"])
        },

        /* 目标元素所在的组件卸载 */
        beforeUnmount(el: HTMLElement, binding: DirectiveBinding, vnode: VNode & MyVNode2) {
            el.removeEventListener(vnode["eventType"], vnode["eventHandler"])
        },
    }
}